/*
 * @Description:散列表
 * @Autor: wangxin
 * @Date: 2020-06-13 16:29:58
 * @LastEditTime: 2020-06-13 23:30:04
 */
/**
 * 键值类对象
 */
class ValuePair {
  constructor(key, value) {
    this.key = key
    this.value = value
  }
  toString() {
    return `[${this.key}:${this.value}]`
  }
}

/**
 * 哈希表类
 */
class HashTable {
  constructor(toStrFn = this.defauiltToString) {
    this.toStrFn = toStrFn
    this.table = {}
  }

  /**
   * 将key转化为字符串
   */
  defauiltToString(item) {
    if (item === null) {
      return 'NULL'
    } else if (item === undefined) {
      return 'UNDEFINED'
    } else if (typeof item === 'string' || item instanceof String) {
      return `${item}`
    }
    return item.toString()
  }

  /**
   * 哈希函数
   */
  loseHashCode(key) {
    if (typeof key === 'number') {
      return key
    }
    const tableKey = this.toStrFn(key)
    let hash = 0
    for (let i = 0; i < tableKey.length; i++) {
      hash += tableKey.charCodeAt(i)
    }
    return hash % 37
  }

  /**
   * 转换key值为哈希值
   */
  hashCode(key) {
    return this.loseHashCode(key)
  }

  /**
   * 向散列表增加一个新的项（也能更新散列表）
   */
  put(key, value) {
    if (key !== null && value !== null) {
      const position = this.hashCode(key)
      this.table[position] = new ValuePair(key, value)
      return true
    }
    return false
  }

  /**
   * 从散列表中获取一个值
   */
  get(key) {
    const valuePair = this.table[this.hashCode(key)]
    return valuePair == null ? undefined : valuePair.value
  }

  /**
   * 从散列表中移除一个数
   */
  remove(key) {
    const hash = this.hashCode(key)
    const valuePair = this.table[hash]
    if (valuePair !== null) {
      // this.table[hash] = null
      delete this.table[hash]
      return true
    }
    return false
  }

  size() {
    return Object.keys(this.table).length
  }

  isEmpty() {
    return this.size() === 0
  }

  toString() {
    if (this.isEmpty()) {
      return ''
    }
    const keys = Object.keys(this.table)
    let objStrng = `{${keys[0]}--${this.table[keys[0]].toString()}}`
    for (let i = 1; i < keys.length; i++) {
      objStrng = `${objStrng},${keys[i]}--${this.table[keys[i]].toString()}`
    }
    return objStrng
  }
}

// 代码测试
const hash = new HashTable()
hash.put('Nathan', 'Nathan.com')
// hash.put('Sargeras', 'Sargeras.com')

hash.put('Jack', 'Jack.com')
// hash.put('Athelstan', 'Athelstan.com')

hash.put('Jamie', 'Jamie.com')
// hash.put('Sue', 'Sue.com')

console.log(hash.toString())
